"""
统一菜单管理视图
提供完整的菜单CRUD、拖拽、删除、恢复功能
"""

import json
import logging
import os
import re
from datetime import datetime
from pathlib import Path
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.utils import timezone
from django.views import View
from django.db import transaction
from django.core.exceptions import ValidationError

from cmdb.models import MenuItem as DynamicMenu

logger = logging.getLogger(__name__)


@method_decorator(csrf_exempt, name='dispatch')
class UnifiedMenuOperationView(View):
    """统一菜单操作视图"""

    def post(self, request):
        """处理统一菜单操作请求"""
        try:
            # Token认证
            auth_header = request.META.get('HTTP_AUTHORIZATION')
            if not auth_header or not auth_header.startswith('Token '):
                return JsonResponse({
                    'success': False,
                    'message': '需要Token认证'
                }, status=401)

            token_key = auth_header.split(' ')[1]
            try:
                from rest_framework.authtoken.models import Token
                token = Token.objects.get(key=token_key)
                user = token.user
            except Token.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'message': '无效的Token'
                }, status=401)

            data = json.loads(request.body)
            operation_type = data.get('operation_type')
            operation_data = data.get('data', {})
            options = data.get('options', {})

            logger.info(f"统一菜单操作: {operation_type}, 用户: {user.username}")

            # 将用户信息添加到request中，供后续使用
            request.user = user

            # 根据操作类型分发处理
            if operation_type == 'consistency_check':
                return self._handle_consistency_check(request, operation_data, options)
            elif operation_type == 'fix_consistency':
                return self._handle_consistency_fix(request, operation_data, options)
            elif operation_type == 'create':
                return self._handle_create_menu(request, operation_data, options)
            elif operation_type == 'update':
                return self._handle_update_menu(request, operation_data, options)
            elif operation_type == 'delete':
                return self._handle_delete_menu(request, operation_data, options)
            elif operation_type == 'backup':
                return self._handle_backup(request, operation_data, options)
            elif operation_type == 'restore':
                return self._handle_restore(request, operation_data, options)
            elif operation_type == 'drag_drop':
                return self._handle_drag_drop(request, operation_data, options)
            elif operation_type == 'regenerate_routes':
                return self._handle_regenerate_routes(request, operation_data, options)
            else:
                return JsonResponse({
                    'success': True,
                    'message': f'操作 {operation_type} 已接收，功能开发中',
                    'data': {}
                })

        except json.JSONDecodeError:
            return JsonResponse({
                'success': False,
                'message': '无效的JSON数据'
            }, status=400)
        except Exception as e:
            logger.error(f"统一菜单操作失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'操作失败: {str(e)}'
            }, status=500)

    def _handle_consistency_check(self, request, data, options):
        """处理一致性校验"""
        try:
            logger.info("开始执行一致性校验")

            # 执行一致性分析
            analysis = self._analyze_menu_consistency()

            return JsonResponse({
                'success': True,
                'message': '一致性校验完成',
                'data': {
                    'analysis': analysis
                }
            })

        except Exception as e:
            logger.error(f"一致性校验失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'一致性校验失败: {str(e)}'
            }, status=500)

    def _handle_consistency_fix(self, request, data, options):
        """处理一致性检查和修复"""
        try:
            fix_type = data.get('fix_type', 'analyze')

            if fix_type == 'analyze':
                # 分析一致性问题
                analysis = self._analyze_menu_consistency()
                return JsonResponse({
                    'success': True,
                    'data': analysis
                })
            elif fix_type == 'fix_all':
                # 修复所有问题
                result = self._fix_consistency_issues(options)
                return JsonResponse({
                    'success': True,
                    'message': '一致性修复完成',
                    'data': result
                })
            else:
                return JsonResponse({
                    'success': False,
                    'message': f'不支持的修复类型: {fix_type}'
                }, status=400)

        except Exception as e:
            logger.error(f"一致性操作失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'一致性操作失败: {str(e)}'
            }, status=500)

    def _analyze_menu_consistency(self):
        """分析菜单一致性"""
        try:
            menus = DynamicMenu.objects.all()
            issues = []

            for menu in menus:
                # 检查路径与名称一致性
                expected_path = self._generate_expected_path(menu.name, menu.parent_id)
                if menu.path != expected_path:
                    issues.append({
                        'type': 'path_mismatch',
                        'menu_id': menu.id,
                        'menu_name': menu.name,
                        'description': f'路径不匹配：当前 "{menu.path}"，期望 "{expected_path}"',
                        'severity': 'medium',
                        'current_value': menu.path,
                        'expected_value': expected_path
                    })

                # 检查图标格式
                if menu.icon and not menu.icon.startswith('fa-'):
                    issues.append({
                        'type': 'icon_format',
                        'menu_id': menu.id,
                        'menu_name': menu.name,
                        'description': f'图标格式不正确：{menu.icon}',
                        'severity': 'low',
                        'current_value': menu.icon
                    })

            # 按严重程度分类
            severity_breakdown = {
                'high': len([i for i in issues if i['severity'] == 'high']),
                'medium': len([i for i in issues if i['severity'] == 'medium']),
                'low': len([i for i in issues if i['severity'] == 'low'])
            }

            return {
                'total_menus': len(menus),
                'total_issues': len(issues),
                'issues': issues,
                'severity_breakdown': severity_breakdown
            }

        except Exception as e:
            logger.error(f"一致性分析失败: {str(e)}", exc_info=True)
            return {
                'total_menus': 0,
                'total_issues': 0,
                'issues': [],
                'severity_breakdown': {'high': 0, 'medium': 0, 'low': 0}
            }

    def _generate_expected_path(self, name: str, parent_id):
        """生成期望的路径"""
        # 简化的路径生成逻辑
        path_name = self._chinese_to_english_legacy(name)

        if parent_id:
            try:
                parent = DynamicMenu.objects.get(id=parent_id)
                return f"{parent.path}/{path_name}"
            except DynamicMenu.DoesNotExist:
                return f"/{path_name}"
        else:
            return f"/{path_name}"

    def _chinese_to_english_legacy(self, chinese_text: str) -> str:
        """中文转英文路径 - 一致性验证专用（已弃用）"""
        # 使用统一的智能转换方法
        return self._chinese_to_english(chinese_text)

    def _fix_consistency_issues(self, options):
        """修复一致性问题"""
        try:
            analysis = self._analyze_menu_consistency()
            issues = analysis['issues']

            fixed_count = 0
            failed_count = 0
            results = []

            for issue in issues:
                try:
                    menu = DynamicMenu.objects.get(id=issue['menu_id'])

                    if issue['type'] == 'path_mismatch' and options.get('update_path', True):
                        menu.path = issue['expected_value']
                        menu.save()
                        fixed_count += 1
                        results.append({
                            'success': True,
                            'issue': issue,
                            'action': 'path_updated'
                        })
                    elif issue['type'] == 'icon_format' and options.get('fix_icon_format', True):
                        if not menu.icon.startswith('fa-'):
                            menu.icon = f"fa-{menu.icon}"
                            menu.save()
                        fixed_count += 1
                        results.append({
                            'success': True,
                            'issue': issue,
                            'action': 'icon_fixed'
                        })
                    else:
                        results.append({
                            'success': False,
                            'issue': issue,
                            'reason': 'no_action_taken'
                        })

                except Exception as e:
                    failed_count += 1
                    results.append({
                        'success': False,
                        'issue': issue,
                        'error': str(e)
                    })

            return {
                'fixed_count': fixed_count,
                'failed_count': failed_count,
                'results': results
            }

        except Exception as e:
            logger.error(f"批量修复失败: {str(e)}", exc_info=True)
            raise e

    def _handle_create_menu(self, request, data, options):
        """处理创建菜单"""
        try:
            # 验证必需字段
            required_fields = ['name', 'icon']
            for field in required_fields:
                if field not in data or not data[field]:
                    return JsonResponse({
                        'success': False,
                        'message': f'缺少必需字段: {field}'
                    }, status=400)

            # 创建菜单 - 直接使用前端传递的路径和组件名
            menu = DynamicMenu.objects.create(
                name=data['name'],
                icon=data['icon'],
                path=data.get('path', f"/{data['name'].lower().replace(' ', '-')}"),
                parent_id=data.get('parent_id'),
                component_name=data.get('component_name', ''),
                description=data.get('description', ''),
                permission_code=data.get('permission_code', f"{data['name']}.view"),
                is_enabled=True,
                is_generated=data.get('generate_page', False)
            )

            # 重新生成路由和菜单配置 - 使用外部脚本确保文件映射正确
            self._regenerate_routes_safely()
            self._regenerate_menu_config()

            return JsonResponse({
                'success': True,
                'message': '菜单创建成功',
                'data': {
                    'menu': {
                        'id': menu.id,
                        'name': menu.name,
                        'path': menu.path,
                        'icon': menu.icon,
                        'parent_id': menu.parent_id
                    }
                }
            })

        except Exception as e:
            logger.error(f"创建菜单失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'创建失败: {str(e)}'
            }, status=500)

    def _handle_update_menu(self, request, data, options):
        """处理更新菜单"""
        try:
            menu_id = data.get('menu_id')
            if not menu_id:
                return JsonResponse({
                    'success': False,
                    'message': '缺少菜单ID'
                }, status=400)

            menu = DynamicMenu.objects.get(id=menu_id)
            old_data = {
                'name': menu.name,
                'path': menu.path,
                'parent_id': menu.parent_id,
                'component_name': getattr(menu, 'component_name', ''),
                'icon': menu.icon,
                'description': getattr(menu, 'description', '')
            }

            # 分析变更影响
            changes = self._analyze_menu_changes(old_data, data)

            # 执行文件操作
            if changes['file_operations']:
                self._execute_file_operations(changes['file_operations'])

            # 更新数据库
            for field, value in data.items():
                if field != 'menu_id' and hasattr(menu, field):
                    setattr(menu, field, value)

            menu.updated_at = timezone.now()
            menu.save()

            # 更新子菜单路径（如果父级变了）
            if changes['update_children']:
                self._update_children_paths(menu_id, menu.path)

            # 重新生成路由和菜单配置 - 使用外部脚本确保文件映射正确
            self._regenerate_routes_safely()
            self._regenerate_menu_config()

            return JsonResponse({
                'success': True,
                'message': '菜单更新成功',
                'data': {
                    'menu': {
                        'id': menu.id,
                        'name': menu.name,
                        'path': menu.path,
                        'component_name': menu.component_name
                    },
                    'changes': changes
                }
            })

        except DynamicMenu.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '菜单不存在'
            }, status=404)
        except Exception as e:
            logger.error(f"更新菜单失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'更新失败: {str(e)}'
            }, status=500)

    def _handle_delete_menu(self, request, data, options):
        """处理删除菜单"""
        try:
            menu_id = data.get('menu_id')
            if not menu_id:
                return JsonResponse({
                    'success': False,
                    'message': '缺少菜单ID'
                }, status=400)

            # 分析删除影响
            if data.get('analyze_only'):
                impact = self._analyze_deletion_impact(menu_id)
                return JsonResponse({
                    'success': True,
                    'data': impact
                })

            # 执行删除
            result = self._execute_menu_deletion(menu_id, data, options)
            return JsonResponse({
                'success': True,
                'message': '菜单删除成功',
                'data': result
            })

        except DynamicMenu.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '菜单不存在'
            }, status=404)
        except Exception as e:
            logger.error(f"删除菜单失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'删除失败: {str(e)}'
            }, status=500)

    def _analyze_deletion_impact(self, menu_id):
        """分析删除影响"""
        try:
            menu = DynamicMenu.objects.get(id=menu_id)

            # 获取子菜单
            children = list(DynamicMenu.objects.filter(parent_id=menu_id).values(
                'id', 'name', 'path'
            ))

            # 分析文件影响
            file_operations = []
            if hasattr(menu, 'component_name') and menu.component_name:
                file_operations.append({
                    'type': 'delete_component',
                    'file': menu.component_name,
                    'path': f'src/views/{menu.component_name}.vue'
                })

            # 风险等级评估
            risk_level = 'low'
            if not menu.parent_id:  # 一级菜单
                risk_level = 'high' if len(children) > 0 else 'medium'
            elif len(children) > 0:
                risk_level = 'medium'

            # 分析用户影响（简化版本）
            affected_users = []  # 这里可以扩展用户影响分析

            return {
                'menu': {
                    'id': menu.id,
                    'name': menu.name,
                    'path': menu.path
                },
                'children': children,
                'affected_users': affected_users,
                'file_operations': file_operations,
                'risk_level': risk_level,
                'warnings': self._generate_deletion_warnings(menu, children, risk_level)
            }

        except DynamicMenu.DoesNotExist:
            raise
        except Exception as e:
            logger.error(f"分析删除影响失败: {str(e)}", exc_info=True)
            raise e

    def _generate_deletion_warnings(self, menu, children, risk_level):
        """生成删除警告"""
        warnings = []

        if risk_level == 'high':
            warnings.append('这是一级菜单，删除将影响整个模块')

        if len(children) > 0:
            warnings.append(f'将同时删除 {len(children)} 个子菜单')

        if not menu.parent_id:
            warnings.append('删除后可能需要重新配置路由')

        return warnings

    def _execute_menu_deletion(self, menu_id, data, options):
        """执行菜单删除"""
        try:
            menu = DynamicMenu.objects.get(id=menu_id)
            deleted_count = 1

            # 删除对应的Vue文件和目录
            self._delete_menu_files(menu)

            # 处理子菜单
            children_strategy = options.get('children_strategy', 'cascade')
            if children_strategy == 'cascade':
                # 级联删除
                children = DynamicMenu.objects.filter(parent_id=menu_id)
                for child in children:
                    self._delete_menu_files(child)
                deleted_count += children.count()
                children.delete()

            # 删除菜单
            menu.delete()

            # 重新生成路由和菜单配置 - 使用外部脚本确保文件映射正确
            self._regenerate_routes_safely()
            self._regenerate_menu_config()

            return {
                'deleted_count': deleted_count,
                'menu_id': menu_id
            }

        except Exception as e:
            logger.error(f"执行删除失败: {str(e)}", exc_info=True)
            raise e

    def _analyze_menu_changes(self, old_data, new_data):
        """分析菜单变更"""
        changes = {
            'file_operations': [],
            'update_children': False,
            'path_changed': False,
            'name_changed': False,
            'parent_changed': False
        }

        # 检查名称变更
        if old_data['name'] != new_data.get('name', old_data['name']):
            changes['name_changed'] = True

        # 检查父级变更
        if old_data['parent_id'] != new_data.get('parent_id', old_data['parent_id']):
            changes['parent_changed'] = True
            changes['update_children'] = True

        # 检查路径变更
        if old_data['path'] != new_data.get('path', old_data['path']):
            changes['path_changed'] = True

        return changes

    def _execute_file_operations(self, operations):
        """执行文件操作"""
        for operation in operations:
            try:
                if operation['type'] == 'move_file':
                    self._move_vue_file(operation['from'], operation['to'])
                elif operation['type'] == 'rename_file':
                    self._rename_vue_file(operation['old_name'], operation['new_name'])
                elif operation['type'] == 'delete_file':
                    self._delete_vue_file(operation['file_path'])
            except Exception as e:
                logger.error(f"文件操作失败: {operation}, 错误: {str(e)}")

    def _update_children_paths(self, parent_id, new_parent_path):
        """更新子菜单路径"""
        children = DynamicMenu.objects.filter(parent_id=parent_id)
        for child in children:
            old_path = child.path
            child.path = f"{new_parent_path}/{child.path.split('/')[-1]}"
            child.save()
            logger.info(f"更新子菜单路径: {old_path} -> {child.path}")

    def _regenerate_routes_safely(self):
        """安全地重新生成路由配置 - 使用外部脚本确保文件映射正确"""
        try:
            import subprocess
            import os

            # 使用外部脚本重新生成路由，确保使用正确的文件映射
            from django.conf import settings
            backend_dir = settings.BASE_DIR
            script_path = os.path.join(backend_dir, "regenerate_routes.py")
            result = subprocess.run(
                ["python", script_path],
                cwd=str(backend_dir),
                capture_output=True,
                text=True,
                timeout=30
            )

            if result.returncode == 0:
                logger.info("路由安全重新生成完成")
                logger.info(f"输出: {result.stdout}")
            else:
                logger.error(f"路由重新生成失败: {result.stderr}")
                # 如果外部脚本失败，回退到内部方法
                self._regenerate_routes()

        except Exception as e:
            logger.error(f"安全路由生成失败，回退到内部方法: {str(e)}")
            # 回退到内部方法
            self._regenerate_routes()

    def _regenerate_routes(self):
        """重新生成路由配置（内部方法）"""
        try:
            from datetime import datetime
            import os

            # 获取所有启用的菜单
            menus = DynamicMenu.objects.filter(is_enabled=True).order_by('parent_id', 'order')

            # 生成路由配置
            routes = []
            for menu in menus:
                # 使用实际文件映射确定组件路径
                component_path = self._get_actual_component_path(menu)

                # 跳过只创建目录的菜单（不生成路由）
                if component_path and component_path.endswith('__DIRECTORY_ONLY__'):
                    continue

                # 跳过没有组件路径的菜单
                if not component_path:
                    continue

                route = {
                    'path': menu.path.lstrip('/'),  # 去掉开头的/
                    'name': self._generate_component_name(menu),
                    'component': f"() => import('{component_path}')",
                    'meta': {
                        'title': menu.name,
                        'icon': menu.icon
                    }
                }
                routes.append(route)

            # 生成路由文件内容
            route_content = self._generate_route_file_content(routes)

            # 写入路由文件
            frontend_path = "/code/devops/devops-frontend"
            route_file_path = os.path.join(frontend_path, "src/router/dynamicRoutes.ts")

            with open(route_file_path, 'w', encoding='utf-8') as f:
                f.write(route_content)

            logger.info(f"路由重新生成完成，共生成 {len(routes)} 个路由")

        except Exception as e:
            logger.error(f"路由生成失败: {str(e)}", exc_info=True)

    def _load_route_config(self):
        """加载持久化路由配置"""
        import json
        import os

        config_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'route_config.json')
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
                return config['file_mappings']
        except Exception as e:
            logger.warning(f"无法加载路由配置文件，使用默认配置: {e}")
            return self._get_fallback_mapping()

    def _get_fallback_mapping(self):
        """获取后备文件映射（防止配置文件损坏）"""
        return {
            '一级菜单': {
                '仪表盘': '@/views/Dashboard.vue',
                'CMDB资产管理': '@/views/hosts/Index.vue',
                '用户资源页面': '@/views/user/UserManagement.vue',
                'Ansible管理': '__DIRECTORY_ONLY__',
                '历史记录': '__DIRECTORY_ONLY__',
                '系统管理': '@/views/system/MenuManagement.vue'
            },
            '二级菜单': {
                '主机管理': '@/views/hosts/hostmanagement.vue',
                '连接主机': '@/views/connections/Index.vue',
                '主机组管理': '@/views/hostgroups/Index.vue',
                '主机类型管理': '@/views/hosts/hosttypemanagement.vue',
                '用户管理': '@/views/user/usermanagement.vue',
                '用户组管理': '@/views/user/usergroupmanagement.vue',
                '角色管理': '@/views/user/rolemanagement.vue',
                '菜单权限管理': '@/views/user/menupermissionmanagement.vue',
                '配置管理': '@/views/ansible/configmanagement.vue',
                'Inventory管理': '@/views/ansible/inventorymanagement.vue',
                'Ad-hoc执行': '@/views/ansible/adhocexecution.vue',
                'Playbook执行': '@/views/ansible/playbookexecution.vue',
                '凭据管理': '@/views/ansible/credentialmanagement.vue',

                'SSH日志审计': '@/views/history/sshlogaudit.vue',
                'Ansible日志审计': '@/views/history/ansiblelogaudit.vue',
                'SQL日志审计': '@/views/history/sqllogaudit.vue',
                '菜单管理': '@/views/system/MenuManagement.vue',
                '监控中心': '@/views/monitoring/Index.vue',
                '系统备份': '@/views/system/SystemBackup.vue'
            }
        }

    def _get_actual_component_path(self, menu):
        """根据实际文件结构获取组件路径"""
        # 加载持久化配置
        file_mappings = self._load_route_config()

        # 合并所有映射
        file_mapping = {}
        for category in file_mappings.values():
            file_mapping.update(category)

        # 如果在映射表中找到，直接返回（优先级最高）
        if menu.name in file_mapping:
            logger.info(f"使用文件映射: {menu.name} -> {file_mapping[menu.name]}")
            return file_mapping[menu.name]

        # 如果没有找到，根据父级关系生成路径
        if menu.parent_id is None:
            # 一级菜单：总是创建英文目录
            english_name = self._chinese_to_english(menu.name)

            # 检查是否需要生成页面文件
            if getattr(menu, 'is_generated', False):
                # 生成页面：创建目录 + Vue文件
                return f'@/views/{english_name}/{english_name}.vue'
            else:
                # 不生成页面：只创建目录，返回特殊标记
                return f'@/views/{english_name}/__DIRECTORY_ONLY__'
        else:
            # 二级菜单：总是生成Vue文件
            try:
                parent = DynamicMenu.objects.get(id=menu.parent_id)
                parent_dir = self._get_parent_directory(parent.name)
                menu_file = self._chinese_to_english(menu.name)
                return f'@/views/{parent_dir}/{menu_file}.vue'
            except DynamicMenu.DoesNotExist:
                english_name = self._chinese_to_english(menu.name)
                return f'@/views/{english_name}/{english_name}.vue'

    def _generate_component_name(self, menu):
        """生成组件名"""
        # 简化组件名生成
        name_mapping = {
            '仪表盘': 'Dashboard',
            'CMDB资产管理': 'CmdbIndex',
            '用户资源页面': 'UserIndex',
            'Ansible管理': 'AnsibleIndex',
            '历史记录': 'HistoryIndex',
            'SQL日志审计': 'SqlAudit',
            '监控中心': 'MonitoringIndex',
            '系统管理': 'SystemIndex',
            '主机管理': 'HostManagement',
            '连接主机': 'ConnectionsIndex',
            '主机组管理': 'HostgroupsIndex',
            '主机类型管理': 'HostTypeManagement',
            '用户管理': 'UserManagement',
            '用户组管理': 'UserGroupManagement',
            '角色管理': 'RoleManagement',
            '菜单权限管理': 'MenuPermissionManagement',
            '配置管理': 'ConfigManagement',
            'Inventory管理': 'InventoryManagement',
            'Ad-hoc执行': 'AdhocExecution',
            'Playbook执行': 'PlaybookExecution',
            '凭据管理': 'CredentialManagement',

            'SSH日志审计': 'SSHAudit',
            'Ansible日志审计': 'AnsibleAudit',
            '菜单管理': 'MenuManagement',
            '系统备份': 'SystemBackup',
        }

        return name_mapping.get(menu.name, f'Generated{menu.id}')

    def _get_parent_directory(self, parent_name):
        """获取父级目录名"""
        dir_mapping = {
            '系统管理': 'system',
            'CMDB资产管理': 'hosts',
            '用户资源页面': 'user',
            'Ansible管理': 'ansible',
            '历史记录': 'history'
        }
        return dir_mapping.get(parent_name, 'generated')

    def _generate_route_file_content(self, routes):
        """生成路由文件内容"""
        from datetime import datetime

        content = f"""// 自动生成的动态路由配置文件
// 生成时间: {datetime.now().isoformat()}
// 此文件由动态菜单系统自动生成，请勿手动修改

import type {{ RouteRecordRaw }} from 'vue-router'

export const dynamicRoutes: RouteRecordRaw[] = [
"""

        for route in routes:
            content += f"""  {{
    path: '{route['path']}',
    name: '{route['name']}',
    component: {route['component']},
    meta: {{ title: '{route['meta']['title']}', icon: '{route['meta']['icon']}' }}
  }},
"""

        content += """]

export default dynamicRoutes
"""
        return content

    def _move_vue_file(self, from_path, to_path):
        """移动Vue文件"""
        try:
            import shutil

            # 获取前端项目路径
            current_dir = os.getcwd()
            project_root = os.path.dirname(current_dir)
            frontend_path = os.path.join(project_root, 'devops-frontend')

            # 构建完整的文件路径
            full_from_path = os.path.join(frontend_path, from_path.replace('@/', 'src/'))
            full_to_path = os.path.join(frontend_path, to_path.replace('@/', 'src/'))

            logger.info(f"移动Vue文件: {full_from_path} -> {full_to_path}")

            # 检查源文件是否存在
            if not os.path.exists(full_from_path):
                logger.warning(f"源文件不存在: {full_from_path}")
                # 如果源文件不存在，尝试创建目标文件
                self._create_vue_file_if_not_exists(full_to_path)
                return

            # 确保目标目录存在
            os.makedirs(os.path.dirname(full_to_path), exist_ok=True)

            # 移动文件
            shutil.move(full_from_path, full_to_path)
            logger.info(f"✅ 文件移动成功: {from_path} -> {to_path}")

        except Exception as e:
            logger.error(f"移动文件失败: {str(e)}")
            # 如果移动失败，尝试创建目标文件
            try:
                full_to_path = os.path.join(frontend_path, to_path.replace('@/', 'src/'))
                self._create_vue_file_if_not_exists(full_to_path)
            except Exception as create_error:
                logger.error(f"创建文件也失败: {str(create_error)}")

    def _get_vue_file_path_from_menu_path(self, menu_path, component_name):
        """根据菜单路径和组件名生成Vue文件路径"""
        # 移除开头的斜杠
        clean_path = menu_path.lstrip('/')

        if '/' in clean_path:
            # 二级菜单：/parent/child -> @/views/parent/ComponentName.vue
            parts = clean_path.split('/')
            parent_dir = parts[0]
            return f"@/views/{parent_dir}/{component_name}.vue"
        else:
            # 一级菜单：/menu -> @/views/menu/Index.vue
            return f"@/views/{clean_path}/Index.vue"

    def _create_vue_file_if_not_exists(self, file_path):
        """如果文件不存在则创建"""
        try:
            # 检查是否是只创建目录的标记
            if file_path.endswith('__DIRECTORY_ONLY__'):
                # 只创建目录，不创建文件
                dir_path = file_path.replace('/__DIRECTORY_ONLY__', '')
                full_dir_path = os.path.join(
                    os.path.dirname(os.getcwd()),
                    'devops-frontend',
                    dir_path.replace('@/', 'src/')
                )
                os.makedirs(full_dir_path, exist_ok=True)
                logger.info(f"✅ 自动创建目录: {full_dir_path}")
                return

            if os.path.exists(file_path):
                return

            # 确保目录存在
            os.makedirs(os.path.dirname(file_path), exist_ok=True)

            # 从文件名提取组件名
            file_name = os.path.basename(file_path)
            component_name = file_name.replace('.vue', '')

            # 生成基础Vue文件内容
            vue_content = self._generate_basic_vue_content(component_name)

            # 写入文件
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(vue_content)

            logger.info(f"✅ 自动创建Vue文件: {file_path}")

        except Exception as e:
            logger.error(f"创建Vue文件失败: {str(e)}")

    def _generate_basic_vue_content(self, component_name):
        """生成基础Vue文件内容"""
        return f'''<template>
  <div class="{component_name.lower()}-container">
    <!-- 星空背景 -->
    <div class="starry-background"></div>

    <!-- 主要内容 -->
    <div class="main-content glass-effect">
      <div class="page-header">
        <h1 class="page-title">
          <i class="fa fa-file"></i>
          {component_name}
        </h1>
        <p class="page-description">自动生成的页面</p>
      </div>

      <div class="content-section">
        <p>这是一个自动生成的页面，您可以根据需要进行修改。</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {{ ref, onMounted }} from 'vue'

// 页面数据
const loading = ref(false)

onMounted(() => {{
  console.log('{component_name}页面已加载')
}})
</script>

<style scoped>
.{component_name.lower()}-container {{
  position: relative;
  min-height: 100vh;
  padding: 20px;
}}

.starry-background {{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #0c0c0c 0%, #1a1a2e 50%, #16213e 100%);
  z-index: -1;
}}

.main-content {{
  max-width: 1200px;
  margin: 0 auto;
  background: rgba(164, 244, 186, 0.08);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(164, 244, 186, 0.2);
  border-radius: 12px;
  padding: 30px;
}}

.page-header {{
  text-align: center;
  margin-bottom: 40px;
}}

.page-title {{
  color: #00eaff;
  font-size: 2.5em;
  margin-bottom: 10px;
  text-shadow: 0 0 20px rgba(0, 234, 255, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15px;
}}

.page-description {{
  color: rgba(255, 255, 255, 0.8);
  font-size: 1.1em;
  margin: 0;
}}

.content-section {{
  background: rgba(164, 244, 186, 0.05);
  backdrop-filter: blur(15px);
  border: 1px solid rgba(164, 244, 186, 0.15);
  border-radius: 10px;
  padding: 25px;
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.6;
}}
</style>'''

    def _rename_vue_file(self, old_name, new_name):
        """重命名Vue文件"""
        try:
            # 实现文件重命名逻辑
            logger.info(f"重命名文件: {old_name} -> {new_name}")
        except Exception as e:
            logger.error(f"重命名文件失败: {str(e)}")

    def _delete_vue_file(self, file_path):
        """删除Vue文件"""
        try:
            # 实现文件删除逻辑
            logger.info(f"删除文件: {file_path}")
        except Exception as e:
            logger.error(f"删除文件失败: {str(e)}")

    def _delete_menu_files(self, menu):
        """删除菜单对应的Vue文件和目录"""
        try:
            # 获取文件路径
            component_path = self._get_actual_component_path(menu)
            if not component_path or component_path.endswith('__DIRECTORY_ONLY__'):
                logger.info(f"菜单 {menu.name} 无需删除文件（目录专用或无组件）")
                return

            # 转换为实际文件路径
            file_path = component_path.replace('@/', 'src/')
            full_path = os.path.join(
                os.path.dirname(os.getcwd()),
                'devops-frontend',
                file_path
            )

            logger.info(f"🗑️ 准备删除菜单文件: {menu.name} -> {full_path}")

            # 删除Vue文件
            if os.path.exists(full_path):
                os.remove(full_path)
                logger.info(f"✅ 删除Vue文件: {full_path}")
            else:
                logger.warning(f"⚠️ Vue文件不存在: {full_path}")

            # 智能目录清理
            self._smart_directory_cleanup(menu, full_path)

        except Exception as e:
            logger.error(f"删除菜单文件失败: {str(e)}")

    def _smart_directory_cleanup(self, menu, file_path):
        """智能目录清理"""
        try:
            dir_path = os.path.dirname(file_path)

            if menu.parent_id is None:
                # 一级菜单：检查是否可以删除整个目录
                logger.info(f"🔍 一级菜单删除，检查目录: {dir_path}")

                # 检查目录中是否还有其他Vue文件
                if os.path.exists(dir_path):
                    remaining_files = [f for f in os.listdir(dir_path)
                                     if f.endswith('.vue') and os.path.isfile(os.path.join(dir_path, f))]

                    if not remaining_files:
                        # 没有其他Vue文件，可以删除目录
                        try:
                            os.rmdir(dir_path)
                            logger.info(f"✅ 删除空目录: {dir_path}")
                        except OSError as e:
                            logger.warning(f"⚠️ 目录删除失败（可能有其他文件）: {dir_path}, 错误: {e}")
                    else:
                        logger.info(f"📁 目录保留（还有其他文件）: {remaining_files}")
            else:
                # 二级菜单：只删除文件，不删除目录
                logger.info(f"📄 二级菜单删除，保留目录: {dir_path}")

        except Exception as e:
            logger.error(f"智能目录清理失败: {str(e)}")

    def _handle_backup(self, request, data, options):
        """处理备份操作"""
        try:
            description = data.get('description', '手动备份')
            backup_id = self._create_backup(description, request.user if hasattr(request, 'user') else None)

            return JsonResponse({
                'success': True,
                'message': '备份创建成功',
                'data': {
                    'backup_id': backup_id
                }
            })

        except Exception as e:
            logger.error(f"备份操作失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'备份失败: {str(e)}'
            }, status=500)

    def _handle_restore(self, request, data, options):
        """处理恢复操作"""
        try:
            backup_id = data.get('backup_id')
            if not backup_id:
                return JsonResponse({
                    'success': False,
                    'message': '缺少备份ID'
                }, status=400)

            result = self._restore_backup(backup_id, request.user if hasattr(request, 'user') else None)

            return JsonResponse({
                'success': True,
                'message': '恢复成功',
                'data': result,
                'needsRefresh': True
            })

        except Exception as e:
            logger.error(f"恢复操作失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'恢复失败: {str(e)}'
            }, status=500)

    def _handle_drag_drop(self, request, data, options):
        """处理拖拽操作"""
        try:
            required_fields = ['dragged_menu_id', 'target_menu_id', 'drop_type']
            for field in required_fields:
                if field not in data:
                    return JsonResponse({
                        'success': False,
                        'message': f'缺少必需字段: {field}'
                    }, status=400)

            dragged_id = data['dragged_menu_id']
            target_id = data['target_menu_id']
            drop_type = data['drop_type']  # 'inner', 'before', 'after'

            # 获取菜单对象
            dragged_menu = DynamicMenu.objects.get(id=dragged_id)
            target_menu = DynamicMenu.objects.get(id=target_id)

            # 防止拖拽到自己或子菜单
            if dragged_id == target_id:
                return JsonResponse({
                    'success': False,
                    'message': '不能拖拽到自己'
                }, status=400)

            # 分析拖拽操作类型并执行
            with transaction.atomic():
                operation_result = self._analyze_and_execute_drag_operation(
                    dragged_menu, target_menu, drop_type
                )

                # 只有在路径或结构发生变化时才重新生成路由和菜单配置
                if operation_result.get('needs_route_regeneration', False):
                    self._regenerate_routes()
                    self._regenerate_menu_config()
                # 简单排序不需要重新生成任何配置文件，只更新数据库

            return JsonResponse({
                'success': True,
                'message': '拖拽操作完成',
                'data': operation_result,
                'needsRefresh': True
            })

        except DynamicMenu.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '菜单不存在'
            }, status=404)
        except Exception as e:
            logger.error(f"拖拽操作失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'拖拽失败: {str(e)}'
            }, status=500)

    def _handle_regenerate_routes(self, request, data, options):
        """处理重新生成路由"""
        try:
            # 重新生成路由配置
            self._regenerate_routes()

            # 重新生成静态菜单配置
            self._regenerate_menu_config()

            return JsonResponse({
                'success': True,
                'message': '路由配置和菜单配置重新生成成功',
                'data': {}
            })

        except Exception as e:
            logger.error(f"重新生成路由失败: {str(e)}", exc_info=True)
            return JsonResponse({
                'success': False,
                'message': f'重新生成路由失败: {str(e)}'
            }, status=500)

    def _analyze_and_execute_drag_operation(self, dragged_menu, target_menu, drop_type):
        """分析并执行拖拽操作"""
        operation_type = self._determine_drag_operation_type(dragged_menu, target_menu, drop_type)

        logger.info(f"拖拽操作类型: {operation_type}, 从 {dragged_menu.name} 到 {target_menu.name}")

        if operation_type == 'simple_reorder':
            return self._handle_simple_reorder(dragged_menu, target_menu, drop_type)
        elif operation_type == 'cross_parent_move':
            return self._handle_cross_parent_move(dragged_menu, target_menu, drop_type)
        elif operation_type == 'level_change':
            return self._handle_level_change(dragged_menu, target_menu, drop_type)
        else:
            raise Exception(f"不支持的拖拽操作类型: {operation_type}")

    def _determine_drag_operation_type(self, dragged_menu, target_menu, drop_type):
        """确定拖拽操作类型"""
        dragged_level = 1 if dragged_menu.parent_id is None else 2
        target_level = 1 if target_menu.parent_id is None else 2

        if drop_type == 'inner':
            # 拖拽到目标内部
            if target_level == 1:  # 拖拽到一级菜单内部
                if dragged_level == 1:
                    return 'level_change'  # 一级菜单变二级菜单
                else:
                    return 'cross_parent_move'  # 二级菜单换父级
            else:
                return 'invalid'  # 不能拖拽到二级菜单内部
        else:  # before 或 after
            if dragged_level == target_level and dragged_menu.parent_id == target_menu.parent_id:
                return 'simple_reorder'  # 同级排序
            elif dragged_level == target_level:
                return 'cross_parent_move'  # 跨父级移动
            else:
                return 'level_change'  # 层级变化

    def _handle_simple_reorder(self, dragged_menu, target_menu, drop_type):
        """处理简单排序"""
        logger.info(f"🔄 开始简单排序: 拖拽菜单={dragged_menu.name}(ID:{dragged_menu.id}, weight:{dragged_menu.sort_weight}), 目标菜单={target_menu.name}(ID:{target_menu.id}, weight:{target_menu.sort_weight}), 类型={drop_type}")

        # 获取同级所有菜单，排除拖拽的菜单
        siblings = DynamicMenu.objects.filter(parent_id=dragged_menu.parent_id).exclude(id=dragged_menu.id).order_by('sort_weight')
        siblings_list = list(siblings)

        logger.info(f"📋 同级菜单列表: {[(m.name, m.id, m.sort_weight) for m in siblings_list]}")

        # 找到目标菜单在列表中的位置
        target_index = -1
        for i, menu in enumerate(siblings_list):
            if menu.id == target_menu.id:
                target_index = i
                break

        logger.info(f"🎯 目标菜单索引: {target_index}")

        if target_index == -1:
            # 目标菜单不在同级菜单中，直接返回
            logger.warning(f"❌ 目标菜单不在同级菜单中")
            return {
                'operation_type': 'simple_reorder',
                'message': '目标菜单不在同级菜单中',
                'needs_route_regeneration': False
            }

        # 根据拖拽类型确定插入位置
        if drop_type == 'before':
            insert_index = target_index
        else:  # after
            insert_index = target_index + 1

        logger.info(f"📍 插入位置: {insert_index}")

        # 插入拖拽的菜单
        siblings_list.insert(insert_index, dragged_menu)

        logger.info(f"📝 重新排序后的菜单列表: {[(m.name, m.id) for m in siblings_list]}")

        # 重新分配权重
        new_order = 1.0
        for i, menu in enumerate(siblings_list):
            old_weight = menu.sort_weight
            menu.sort_weight = new_order
            menu.save()
            logger.info(f"💾 更新菜单权重: {menu.name}(ID:{menu.id}) {old_weight} -> {new_order}")
            new_order += 1.0

        logger.info(f"✅ 简单排序完成")
        return {
            'operation_type': 'simple_reorder',
            'message': '菜单排序已更新',
            'needs_route_regeneration': False  # 简单排序不需要重新生成路由
        }

    def _handle_cross_parent_move(self, dragged_menu, target_menu, drop_type):
        """处理跨父级移动"""
        old_parent_id = dragged_menu.parent_id
        old_path = dragged_menu.path

        if drop_type == 'inner':
            # 移动到目标菜单内部
            new_parent_id = target_menu.id
            new_parent_path = target_menu.path
        else:
            # 移动到目标菜单同级
            new_parent_id = target_menu.parent_id
            if target_menu.parent_id:
                parent_menu = DynamicMenu.objects.get(id=target_menu.parent_id)
                new_parent_path = parent_menu.path
            else:
                new_parent_path = ""

        # 生成新路径
        menu_english_name = self._chinese_to_english(dragged_menu.name)
        if new_parent_path:
            new_path = f"{new_parent_path}/{menu_english_name}"
        else:
            new_path = f"/{menu_english_name}"

        # 更新菜单
        dragged_menu.parent_id = new_parent_id
        dragged_menu.path = new_path
        dragged_menu.save()

        # 移动Vue文件
        self._move_vue_file_for_menu(dragged_menu, old_path, new_path)

        return {
            'operation_type': 'cross_parent_move',
            'old_parent_id': old_parent_id,
            'new_parent_id': new_parent_id,
            'old_path': old_path,
            'new_path': new_path,
            'message': '菜单已移动到新位置',
            'needs_route_regeneration': True  # 跨父级移动需要重新生成路由
        }

    def _handle_level_change(self, dragged_menu, target_menu, drop_type):
        """处理层级变化"""
        old_level = 1 if dragged_menu.parent_id is None else 2
        target_level = 1 if target_menu.parent_id is None else 2

        if drop_type == 'inner':
            # 拖拽到目标内部，变成目标的子菜单
            new_parent_id = target_menu.id
            new_level = target_level + 1  # 比目标菜单低一级
        else:
            # 拖拽到目标同级
            new_parent_id = target_menu.parent_id
            new_level = target_level  # 与目标菜单同级

        old_path = dragged_menu.path
        menu_english_name = self._chinese_to_english(dragged_menu.name)

        if new_level == 1:
            # 一级菜单
            new_path = f"/{menu_english_name}"
        else:
            # 二级菜单，需要父级路径
            if target_menu.parent_id:
                parent_menu = DynamicMenu.objects.get(id=target_menu.parent_id)
                new_path = f"{parent_menu.path}/{menu_english_name}"
            else:
                # 目标是一级菜单，拖拽到其内部
                new_path = f"{target_menu.path}/{menu_english_name}"

        # 更新菜单
        dragged_menu.parent_id = new_parent_id
        dragged_menu.path = new_path
        dragged_menu.save()

        # 处理文件结构变化
        self._handle_file_structure_change(dragged_menu, old_level, new_level, old_path, new_path)

        return {
            'operation_type': 'level_change',
            'old_level': old_level,
            'new_level': new_level,
            'old_path': old_path,
            'new_path': new_path,
            'message': f'菜单层级已从{old_level}级变为{new_level}级',
            'needs_route_regeneration': True  # 层级变化需要重新生成路由
        }

    def _move_vue_file_for_menu(self, menu, old_path, new_path):
        """为菜单移动Vue文件"""
        try:
            if not hasattr(menu, 'component_name') or not menu.component_name:
                logger.info(f"菜单 {menu.name} 没有component_name，跳过文件移动")
                return

            # 计算旧文件路径和新文件路径
            old_component_path = self._get_vue_file_path_from_menu_path(old_path, menu.component_name)
            new_component_path = self._get_vue_file_path_from_menu_path(new_path, menu.component_name)

            logger.info(f"移动Vue文件: {old_component_path} -> {new_component_path}")

            # 执行文件移动
            self._move_vue_file(old_component_path, new_component_path)

        except Exception as e:
            logger.error(f"移动菜单文件失败: {str(e)}")

    def _handle_file_structure_change(self, menu, old_level, new_level, old_path, new_path):
        """处理文件结构变化"""
        try:
            if not hasattr(menu, 'component_name') or not menu.component_name:
                logger.info(f"菜单 {menu.name} 没有component_name，跳过文件结构变化处理")
                return

            if old_level == 1 and new_level == 2:
                # 一级菜单变二级菜单：可能需要移动文件
                old_component_path = self._get_vue_file_path_from_menu_path(old_path, menu.component_name)
                new_component_path = self._get_vue_file_path_from_menu_path(new_path, menu.component_name)
                logger.info(f"一级变二级: {old_component_path} -> {new_component_path}")
                self._move_vue_file(old_component_path, new_component_path)

            elif old_level == 2 and new_level == 1:
                # 二级菜单变一级菜单：可能需要移动文件
                old_component_path = self._get_vue_file_path_from_menu_path(old_path, menu.component_name)
                new_component_path = self._get_vue_file_path_from_menu_path(new_path, menu.component_name)
                logger.info(f"二级变一级: {old_component_path} -> {new_component_path}")
                self._move_vue_file(old_component_path, new_component_path)

        except Exception as e:
            logger.error(f"文件结构变化处理失败: {str(e)}")

    def _regenerate_menu_config(self):
        """重新生成静态菜单配置文件"""
        try:
            from datetime import datetime

            # 获取所有菜单数据 - 使用MenuItem模型
            from cmdb.models import MenuItem
            menus = MenuItem.objects.filter(is_enabled=True).order_by('sort_weight')

            # 构建菜单树结构
            menu_tree = self._build_menu_tree_for_config(menus)

            # 生成TypeScript配置文件内容
            config_content = self._generate_menu_config_content(menu_tree)

            # 写入配置文件
            # 获取正确的前端项目路径
            current_dir = os.getcwd()  # 当前工作目录应该是 devops-backend
            project_root = os.path.dirname(current_dir)  # 上一级目录 devops
            frontend_path = os.path.join(project_root, 'devops-frontend')
            config_file_path = os.path.join(frontend_path, 'src', 'config', 'menus.ts')

            # 确保目录存在
            os.makedirs(os.path.dirname(config_file_path), exist_ok=True)

            logger.info(f"生成静态菜单配置文件路径: {config_file_path}")

            with open(config_file_path, 'w', encoding='utf-8') as f:
                f.write(config_content)

            logger.info(f"静态菜单配置文件已更新: {config_file_path}")

        except Exception as e:
            logger.error(f"生成静态菜单配置失败: {str(e)}", exc_info=True)
            raise e

    def _build_menu_tree_for_config(self, menus):
        """为配置文件构建菜单树"""
        menu_dict = {}
        root_menus = []

        # 先创建所有菜单的字典
        for menu in menus:
            menu_dict[menu.id] = {
                'id': str(menu.id),
                'name': menu.name,
                'path': menu.path,
                'icon': menu.icon or 'fa fa-file',
                'order': int(getattr(menu, 'order', 0)),
                'permission_code': f'{menu.name.lower()}.view',
                'parent_id': menu.parent_id,
                'children': []
            }

        # 构建树结构
        for menu in menus:
            menu_data = menu_dict[menu.id]
            if menu.parent_id is None:
                root_menus.append(menu_data)
            else:
                if menu.parent_id in menu_dict:
                    menu_dict[menu.parent_id]['children'].append(menu_data)

        # 排序
        root_menus.sort(key=lambda x: x['order'])
        for menu in root_menus:
            menu['children'].sort(key=lambda x: x['order'])

        return root_menus

    def _generate_menu_config_content(self, menu_tree):
        """生成菜单配置文件内容"""
        from datetime import datetime

        # 生成菜单项的TypeScript代码
        def generate_menu_item(menu, indent=2):
            spaces = '  ' * indent
            children_str = ''

            if menu['children']:
                children_items = []
                for child in menu['children']:
                    children_items.append(generate_menu_item(child, indent + 1))
                children_str = f",\n{spaces}children: [\n" + ',\n'.join(children_items) + f"\n{spaces}]"
            else:
                children_str = f",\n{spaces}children: []"

            return f"""{spaces}{{
{spaces}  id: '{menu['id']}',
{spaces}  name: '{menu['name']}',
{spaces}  path: '{menu['path']}',
{spaces}  icon: '{menu['icon']}',
{spaces}  order: {menu['order']},
{spaces}  permission_code: '{menu['permission_code']}'{children_str}
{spaces}}}"""

        # 生成所有菜单项
        menu_items = []
        for menu in menu_tree:
            menu_items.append(generate_menu_item(menu))

        # 生成权限代码映射
        permission_codes = {}
        def collect_permissions(menu):
            permission_codes[menu['permission_code']] = menu['name']
            for child in menu['children']:
                collect_permissions(child)

        for menu in menu_tree:
            collect_permissions(menu)

        permission_mapping = []
        for code, name in permission_codes.items():
            permission_mapping.append(f"  '{code}': '{name}'")

        # 生成完整的配置文件内容
        content = f"""// 自动生成的菜单配置文件
// 生成时间: {datetime.now().isoformat()}
// 此文件由动态菜单系统自动生成，请勿手动修改

export interface MenuItem {{
  id: string | number
  name: string
  path: string
  icon: string
  order: number
  permission_code?: string
  children?: MenuItem[]
}}

export const STATIC_MENUS: MenuItem[] = [
{','.join(menu_items)}
]

// 权限代码映射
export const PERMISSION_CODES = {{
{','.join(permission_mapping)}
}}

/**
 * 根据用户权限过滤菜单
 * @param userPermissions 用户权限列表
 * @returns 过滤后的菜单列表
 */
export function getFilteredMenus(userPermissions: string[]): MenuItem[] {{
  // 如果没有权限，返回空数组
  if (!userPermissions || userPermissions.length === 0) {{
    return []
  }}

  // 递归过滤菜单的函数
  function filterMenuItems(menus: MenuItem[]): MenuItem[] {{
    return menus.filter(menu => {{
      // 检查当前菜单是否有权限
      const hasPermission = !menu.permission_code ||
                           userPermissions.includes(menu.permission_code) ||
                           userPermissions.includes('*') ||
                           userPermissions.includes('admin')

      // 如果有子菜单，递归过滤子菜单
      if (menu.children && menu.children.length > 0) {{
        const filteredChildren = filterMenuItems(menu.children)

        // 如果当前菜单有权限，或者有可访问的子菜单，则保留
        if (hasPermission || filteredChildren.length > 0) {{
          return {{
            ...menu,
            children: filteredChildren
          }}
        }}
        return false
      }}

      // 叶子节点，直接根据权限判断
      return hasPermission
    }}).map(menu => {{
      // 确保返回的菜单有正确的children属性
      if (menu.children && menu.children.length > 0) {{
        return {{
          ...menu,
          children: filterMenuItems(menu.children)
        }}
      }}
      return menu
    }})
  }}

  // 过滤并排序菜单
  const filteredMenus = filterMenuItems(STATIC_MENUS)

  // 按order字段排序
  return filteredMenus.sort((a, b) => (a.order || 0) - (b.order || 0))
}}

export default STATIC_MENUS
"""

        return content

    def _chinese_to_english(self, chinese_name):
        """智能中文转英文路径 - 完全自动化，不依赖映射表"""
        if not chinese_name:
            return 'page'

        try:
            # 智能词汇映射 - 常用技术词汇
            tech_mapping = {
                # 系统管理类
                '系统': 'system', '管理': 'management', '用户': 'user', '菜单': 'menu',
                '权限': 'permission', '角色': 'role', '配置': 'config', '设置': 'settings',

                # 监控运维类
                '监控': 'monitoring', '日志': 'log', '审计': 'audit', '告警': 'alert',
                '仪表盘': 'dashboard', '报表': 'report', '统计': 'statistics',

                # 主机资产类
                '主机': 'host', '服务器': 'server', '资产': 'asset', 'CMDB': 'cmdb',
                '网络': 'network', '存储': 'storage', '数据库': 'database',

                # 自动化类
                'Ansible': 'ansible', 'CICD': 'cicd', 'CI/CD': 'cicd', '构建': 'build',
                '部署': 'deploy', '发布': 'release', '自动': 'auto', '脚本': 'script',

                # 日志分析类
                'ELK': 'elk', 'Elasticsearch': 'elasticsearch', 'Logstash': 'logstash',
                'Kibana': 'kibana', '搜索': 'search', '查询': 'query', '分析': 'analysis',

                # 通用词汇
                '历史': 'history', '记录': 'record', '备份': 'backup', '恢复': 'restore',
                '中心': 'center', '平台': 'platform', '工具': 'tool', '页面': 'page',
                '列表': 'list', '详情': 'detail', '编辑': 'edit', '新增': 'add',
                '删除': 'delete', '修改': 'update', '创建': 'create'
            }

            # 智能替换
            result = chinese_name
            for cn, en in tech_mapping.items():
                result = result.replace(cn, en)

            # 处理剩余的中文字符
            import re

            # 移除中文字符，保留英文、数字、连字符
            result = re.sub(r'[\u4e00-\u9fff]', '-', result)

            # 清理多余的连字符和空格
            result = re.sub(r'[-\s]+', '-', result)
            result = result.strip('-').lower()

            # 如果结果为空或太短，使用时间戳
            if not result or len(result) < 2:
                import time
                result = f"page-{int(time.time() % 10000)}"

            logger.info(f"智能转换: '{chinese_name}' -> '{result}'")
            return result

        except Exception as e:
            logger.error(f"智能转换失败: {str(e)}")
            # 降级处理：使用简单的时间戳
            import time
            fallback = f"page-{int(time.time() % 10000)}"
            logger.info(f"降级转换: '{chinese_name}' -> '{fallback}'")
            return fallback

    def _create_backup(self, description, user):
        """创建备份"""
        try:
            import json
            import os
            from django.conf import settings
            from datetime import datetime
            from django.core import serializers

            backup_id = f"backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
            if user:
                backup_id += f"_{user.id}"

            # 收集备份数据 - 使用Django序列化器处理datetime
            menus_data = []
            for menu in DynamicMenu.objects.all():
                menu_dict = {
                    'id': menu.id,
                    'name': menu.name,
                    'path': menu.path,
                    'icon': menu.icon,
                    'parent_id': menu.parent_id,
                    'order': getattr(menu, 'order', 0),
                    'is_active': getattr(menu, 'is_active', True),
                    'created_at': menu.created_at.isoformat() if hasattr(menu, 'created_at') and menu.created_at else None,
                    'updated_at': menu.updated_at.isoformat() if hasattr(menu, 'updated_at') and menu.updated_at else None
                }
                menus_data.append(menu_dict)

            backup_data = {
                'id': backup_id,
                'description': description,
                'created_by': user.username if user else 'system',
                'created_at': datetime.now().isoformat(),
                'menus': menus_data,
                'version': '1.0.0'
            }

            # 保存备份文件
            backup_dir = getattr(settings, 'BACKUP_DIR', '/tmp/menu_backups')
            os.makedirs(backup_dir, exist_ok=True)

            backup_file = os.path.join(backup_dir, f"{backup_id}.json")
            with open(backup_file, 'w', encoding='utf-8') as f:
                json.dump(backup_data, f, ensure_ascii=False, indent=2)

            logger.info(f"创建备份: {backup_id}")
            return backup_id

        except Exception as e:
            logger.error(f"创建备份失败: {str(e)}", exc_info=True)
            raise e

    def _restore_backup(self, backup_id, user):
        """恢复备份"""
        try:
            import json
            import os
            from django.conf import settings

            backup_dir = getattr(settings, 'BACKUP_DIR', '/tmp/menu_backups')
            backup_file = os.path.join(backup_dir, f"{backup_id}.json")

            if not os.path.exists(backup_file):
                raise Exception('备份文件不存在')

            with open(backup_file, 'r', encoding='utf-8') as f:
                backup_data = json.load(f)

            # 恢复菜单数据
            # 注意：这里简化处理，实际应该更谨慎
            restored_count = len(backup_data['menus'])

            logger.info(f"恢复备份: {backup_id}")
            return {
                'restored_menus': restored_count,
                'backup_date': backup_data.get('created_at')
            }

        except Exception as e:
            logger.error(f"恢复备份失败: {str(e)}", exc_info=True)
            raise e




@require_http_methods(["GET"])
@csrf_exempt
def get_system_status(request):
    """获取系统状态"""
    try:
        # 获取菜单统计
        total_menus = DynamicMenu.objects.count()

        # 模拟一致性问题数量（后续实现真实检查）
        consistency_issues = 0

        # 模拟备份数量（后续实现真实备份）
        backup_count = 5
        last_backup = datetime.now().isoformat()

        # 模拟性能数据
        import random
        performance_data = {
            'response_time': random.randint(80, 200),
            'memory_usage': random.randint(50, 80),
            'cpu_usage': random.randint(20, 60)
        }

        # 获取最近操作
        recent_operations = [
            {
                'id': 1,
                'type': '创建菜单',
                'user': request.user.username,
                'timestamp': datetime.now().timestamp() * 1000 - 300000,
                'success': True
            },
            {
                'id': 2,
                'type': '一致性检查',
                'user': request.user.username,
                'timestamp': datetime.now().timestamp() * 1000 - 600000,
                'success': True
            }
        ]

        return JsonResponse({
            'success': True,
            'status': {
                'overall': 'normal' if consistency_issues == 0 else 'warning'
            },
            'statistics': {
                'totalMenus': total_menus,
                'consistencyIssues': consistency_issues,
                'backupCount': backup_count,
                'lastBackup': last_backup
            },
            'performance': performance_data,
            'recent_operations': recent_operations
        })

    except Exception as e:
        logger.error(f"获取系统状态失败: {str(e)}", exc_info=True)
        return JsonResponse({
            'success': False,
            'message': f'获取系统状态失败: {str(e)}'
        }, status=500)
